package com.luokangtao.zuul.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.luokangtao.common.entity.RedisKeyCode;
import com.luokangtao.common.entity.Result;
import com.luokangtao.common.entity.StatusCode;
import com.luokangtao.common.handler.BaseException;
import com.luokangtao.common.util.JwtUtil;
import com.luokangtao.zuul.exception.ErrorException;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import javax.servlet.http.HttpServletRequest;

/**
 * 校验当前用户是否已经登陆
 * @author luokangtao
 * @create 2019-07-29 14:48
 */
@Slf4j
public class ManagerFilter extends ZuulFilter {

    @Autowired
    private RedisTemplate redisTemplate;//redis

    @Autowired
    private JwtUtil jwtUtil;

    //filterType()返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型
    //pre:可以在请求路由之前调用 route请求时候 post:在route和error过滤之后被调用 error:处理请求时发生错误时被调用
    @Override
    public String filterType() {
        return "pre";// 前置过滤器
    }
    //通过int值来定义过滤器的执行顺序 越小优先级越高
    @Override
    public int filterOrder() {
        return 0;//优先级为0，数字越大，优先级越低
    }
    //返回一个boolean类型来判断该过滤器是否要执行，所以通过此函数可实现过滤器的开关。在上例中，我们直接返回true，所以该过滤器总是生效
    @Override
    public boolean shouldFilter() {
        return true;//是否执行该过滤器，此处为true，说明需要过滤
    }

    //过滤器具体的逻辑
    @Override
    public Object run() throws ZuulException {
        log.info("zuul过滤器开始执行=========================================");
        //zuul自定带方法
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求头数据
        HttpServletRequest request = currentContext.getRequest();
        //0 判断是否是跨域(如果做跨域请求时候，浏览器会自动发起一个 OPTIONS 方法到服务器。)
        if(request.getMethod().equals("OPTIONS")){
            return null;
        }
        log.info("url:"+request.getRequestURI());
        //1.判断是否是登录
        if (request.getRequestURI().contains("/sys/login")) {
            log.info("这是登陆接口,直接放行===============================");
            return null;
        }
        //放行
        if(request.getRequestURI().contains("/api-docs"))
        {
            log.info("这是swagger接口,直接放行===============================");
            return null;
        }
        String authorization = request.getHeader("Authorization");
        if(StrUtil.hasBlank(authorization)){
            throw new ErrorException("Authorization空值异常",StatusCode.ERROR,"");
        }
        //如果不等于空
        if(StrUtil.isNotBlank(authorization)){
            //获取登录时保存在redis缓存里面的token  然后对比是否登陆
            String id =null;
            try {
                Claims claims = jwtUtil.parseJWT(authorization);
                 id = claims.getId();
            }catch (Exception e){
                log.info("触发异常信息================================================");
                //消息(必填,前台获取),  错误码(必填,前台获取),  异常码
                throw new ErrorException("Token过期",StatusCode.EXPIRED,"");
            }
            BoundHashOperations ops = redisTemplate.boundHashOps(RedisKeyCode.LOGIN);
            log.info("redis缓存里面的数据:[{}]",ops.getOperations());
                if(ops.hasKey(id)){
                    String token = (String) ops.get(id);
                    //如果redis里面的token 和 前端传来的token一样
                    if(token.equalsIgnoreCase(authorization)){
                        log.info("前端传来的token:[{}]",authorization);
                        log.info("redis里面的token:[{}]",token);
                        log.info("这是登陆校验通过,直接放行===============================");
                        return null;
                    }else {
                        //如果当前redis存在key值 但是token不一致
                        log.info("如果当前redis存在key值 但是token不一致===========================================");
                        Long delete = ops.delete(id);
                        log.info("删除redis里面的缓存key值"+delete);
                        throw new ErrorException("Token过期",StatusCode.EXPIRED,"");
                    }
                }else {
                    //如果当前redis不存在key
                    log.info("当前redis的key值不存在===========================================");
                    throw new ErrorException("未授权的访问",StatusCode.ACCESSDENINED,"");
                }
        }
        //3.其它终止执行
        currentContext.setSendZuulResponse(false);//终止运行
        currentContext.setResponseStatusCode(StatusCode.ACCESSDENINED);//http状态码
        //自定义返回值 ACCESS DENINED
        String jsonString = JSONObject.toJSONString(new Result<>(false,StatusCode.ACCESSDENINED,"access denined"));
        currentContext.setResponseBody(jsonString);
        currentContext.getResponse().setContentType("text/html;charset=UTF‐8");
        return null;
    }
}
